package com.firefly.util.utils;

import com.firefly.util.configure.CryptProperties;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.util.Date;
import java.util.Random;


/**
 * @description: 唯一ID生成
 * @author: lzg(萤火科技 ： 854378082 @ qq.com)
 * @date: 2022/10/10
 **/
public class IdUtils {

    // 最近的时间戳
    private static long lastTimestamp = 0;
    //机器id 2位
    private static final String machineId = CryptProperties.getMachineId();
    // 0，并发控制
    private static long sequence = 0L;
    // 序列号的最大值
    private static final int sequenceMax = 9999;

    /**
     * 生成订单号
     */
    public synchronized static String nextId() {
        Date now = new Date();
        String time = DateFormatUtils.format(now, "yyMMddHHmmssSSS");
        long timestamp = now.getTime();
        if (lastTimestamp == timestamp) {
            // 如果上一个timestamp与新产生的相等，则sequence加一(0-4095循环);
            // 对新的timestamp，sequence从0开始
            sequence = sequence + 1 % sequenceMax;
            if (sequence == 0) {
                // 重新生成timestamp
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }
        lastTimestamp = timestamp;
        StringBuilder sb = new StringBuilder(time).append(machineId).append(leftPad(sequence, 6));
        return sb.toString();
    }

    /**
     * 补码
     *
     * @param i
     * @param n
     * @return
     */
    private static String leftPad(long i, int n) {
        String s = String.valueOf(i);
        StringBuilder sb = new StringBuilder();
        final String str = "0123456789";
        final Random random = new Random();
        int c = n - s.length();
        c = c < 0 ? 0 : c;
        for (int t = 0; t < c; t++) {
            final int number = random.nextInt(10);
            sb.append(str.charAt(number));
        }
        return sb.append(s).toString();
    }
    /**
     * 等待下一个毫秒的到来, 保证返回的毫秒数在参数lastTimestamp之后
     */
    private static long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}

